<template>
  <div class="ep-container">
    <el-form-item :label="options.label" :prop="options.name" :show-message="!isDetail" class="ep-form-item">
      <el-upload
        ref="fieldRef"
        class="ep-fileupload-container"
        v-model:file-list="fileList"
        :style="{ width: '100%' }"
        :class="[{ hiddenUploadBtn }]"
        accept="image/*"
        :action="options.action"
        :disabled="options.disabled || options.camera"
        :limit="options.limit"
        :list-type="options.listType"
        :before-upload="handleBeforeUpload"
        :on-success="handleOnSuccess"
        :on-error="handleOnError"
        :on-exceed="handleOnExceed"
        :http-request="handleHttpRequest"
      >
        <el-icon v-if="options.listType === 'picture-card' && !isDetail && !hiddenUploadBtn"><Plus /></el-icon>
        <el-button v-if="options.listType !== 'picture-card' && !isDetail && !hiddenUploadBtn" type="default">{{
          options.btn || '添加'
        }}</el-button>
        <template v-if="options.listType !== 'text'" #file="{ file }">
          <div v-if="options.listType === 'picture'" style="display: flex; width: 100%">
            <img
              v-if="getFileType(file).includes('image/')"
              class="el-upload-list__item-thumbnail"
              :src="file.url"
              alt=""
            />
            <div v-else class="ep-preview-cover-file-icon">
              <!-- <m-icon :name="getIconByFileType(file)" /> -->
            </div>
            <div class="el-upload-list__item-info">
              <a class="el-upload-list__item-name">
                <span class="el-upload-list__item-file-name">{{ file.name }}</span>
              </a>
              <a class="el-upload-list__item-name">
                <span style="color: #a8abb2">{{ Number((file.size || 0) / 1024 / 1024).toFixed(2) + ' MB' }}</span>
              </a>
              <el-progress
                v-if="file.status === 'uploading'"
                type="line"
                :stroke-width="2"
                :percentage="Number(file.percentage || 0)"
                style="margin-top: 0.5rem"
              />
            </div>
            <label v-if="!isDetail" class="el-upload-list__item-status-label">
              <el-icon class="el-icon--upload-success el-icon--check"><Check /></el-icon>
            </label>
            <el-icon v-if="!isDetail" class="el-icon--upload-success el-icon--close"
              ><Close @click="handleRemove(file)"
            /></el-icon>
            <i v-if="!isDetail" class="el-icon--close-tip">按 delete 键可删除</i>
          </div>
          <div v-if="options.listType === 'picture'" class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
              <el-icon v-show="getFileType(file).includes('image/')"><ZoomIn /></el-icon>
            </span>
            <span v-if="isDetail" class="el-upload-list__item-action">
              <el-icon class="action-icon" @click="downloadFile(file)"><Download /></el-icon>
            </span>
          </div>
          <div v-if="options.listType === 'picture-card'" class="flex-center">
            <img
              v-if="getFileType(file).includes('image/')"
              class="el-upload-list__item-thumbnail"
              :src="file.url"
              alt=""
            />
            <div v-else class="ep-preview-cover-file-icon">
              <!-- <m-icon :name="getIconByFileType(file)" /> -->
            </div>
            <el-progress
              v-if="file.status === 'uploading'"
              type="circle"
              :width="90"
              :stroke-width="5"
              :percentage="Number(file.percentage || 0)"
              style="display: flex; justify-content: center; align-items: center"
            />
            <span class="el-upload-list__item-actions">
              <span
                v-if="getFileType(file).includes('image/')"
                class="el-upload-list__item-preview"
                @click="handlePictureCardPreview(file)"
              >
                <el-icon><ZoomIn /></el-icon>
              </span>
              <span v-if="isDetail" class="el-upload-list__item-download" @click="downloadFile(file)">
                <el-icon><Download /></el-icon>
              </span>
              <span v-if="!isDetail" class="el-upload-list__item-delete" @click="handleRemove(file)">
                <el-icon><Delete /></el-icon>
              </span>
            </span>
          </div>
        </template>
        <template #tip>
          <div v-if="options.tip && !isDetail" class="el-upload__tip">
            {{ options.tip }}
          </div>
        </template>
      </el-upload>
    </el-form-item>
  </div>
</template>

<script lang="ts">
import { defineComponent, computed, ref, getCurrentInstance, watch } from 'vue'
import defaultProps from '../props'
import Compressor from 'compressorjs'
import _ from 'lodash'
import { UploadFile, UploadFiles, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'

const name = 'ep-fileupload'
Symbol(name)

export default defineComponent({
  name,
  props: defaultProps,
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    const isDetail = computed(() => props.options.permission > 0)

    const internalInstance = getCurrentInstance()
    const proxy = internalInstance?.proxy

    const fieldRef = ref(null)
    const showViewer = ref(false)

    /** 预览图片 */
    const preview = computed(() => {
      return Array.isArray(fileList.value) && fileList.value.length > 0
    })

    /** 预览图片索引位置 */
    const previewIndex = ref(0)
    const imageIndex = computed(() => {
      if (previewIndex.value > fileList.value.length - 1) {
        return 0
      }
      return previewIndex.value
    })
    /** 预览图片列表 */
    const previewSrcList = computed(() => {
      return fileList.value.map((s) => s.url)
    })
    const prevOverflow = ''

    function closeViewer() {
      document.body.style.overflow = prevOverflow
      showViewer.value = false
    }

    /** 上传文件列表 */
    const fileList = ref<UploadUserFile[]>([])

    /** 设置上传文件列表 */
    const setFileList = (files: UploadFiles) => {
      // const addfiles = _.cloneDeep(files.filter((m) => !fileList.value.find((x) => x.id === m.id)))
      // const { actionBlob } = props.options
      // if (actionBlob) {
      //   addfiles.forEach((file: UploadFile) => {
      //     if (file.id && file.type.includes('image/')) {
      //       // file.url = proxy?.$axios.getUrl(actionBlob + '/' + file.id)
      //     }
      //   })
      // }
      // fileList.value.push(...addfiles)
      console.log('fileList.value :>> ', fileList.value)
    }

    /** PC端下载文件，照片采用downloadByBlob原下载方式 */
    const downloadFile = (file: UploadFile) => {
      const { actionBlob } = props.options
      // proxy?.$axios.download(actionBlob + '/' + file.id)
    }

    /** 移除图片 */
    const handleRemove = (file: UploadFile) => {
      if (isDetail.value) {
        return false
      }
      fileList.value.splice(fileList.value.indexOf(file), 1)
      emit('update:modelValue', fileList.value)
    }
    /** PC预览图片 */
    const handlePictureCardPreview = (file: UploadFile) => {
      if (!preview.value) return
      const index = fileList.value.findIndex((x) => x === file)
      previewIndex.value = index
      document.body.style.overflow = 'hidden'
      showViewer.value = true
    }

    const fileMaxSize = computed(() => {
      return Number(props.options.fileMaxSize || 5) * 1024 * 1024
    })

    /** 上传文件之前的钩子 */
    const handleBeforeUpload = (file: UploadRawFile): any =>
      new Promise((resolve, reject) => {
        /** 判断照片格式 */
        const fileTypes = props.options.fileTypes || []
        if (fileTypes.length > 0) {
          const extFileName = file.name.substring(file.name.lastIndexOf('.') + 1)
          if (!fileTypes.some((ext: string) => getIconByFileType(file) === ext)) {
            proxy?.$message.error(`不支持格式：${extFileName || file.type}`)
            reject()
          }
        }

        /** 判断文件大小 */
        const fileMaxSize = props.options.fileMaxSize || 5
        if (file.size >= Number(fileMaxSize) * 1024 * 1024) {
          proxy?.$message.error(`文件大小已超出：${fileMaxSize}MB`)
          reject()
        }
        if (props.options.reduce && file.type.includes('image')) {
          // 会将图片修正为正确方向
          new Compressor(file, {
            convertSize: 2000000, // 超出大小压缩
            maxWidth: props.options.reduce === 2 ? 1440 : 3024, // 输出图像最大宽度
            quality: props.options.reduce === 2 ? 0.8 : 0.9, // 压缩质量
            success: resolve,
            error(err) {
              console.log(err.message)
              proxy?.$message.error('图片压缩错误！')
              reject()
            }
          })
        } else {
          resolve(file)
        }
      })

    /** 文件上传成功时的钩子 */
    const handleOnSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
      // 回写id
      const { id } = response
      // if (id) uploadFile.id = id
      // uploadFile.type = uploadFile.raw.type
      console.log('uploadFile :>> ', uploadFile)

      // const list = uploadFiles.map((m) => {
      //   const { id, name, type, size } = m
      //   return { id, name, type, size }
      // })
      // emit('update:modelValue', list)
    }
    /** 文件上传失败时的钩子 */
    const handleOnError = () => {
      proxy?.$message.error('上传失败！')
    }
    /** 当超出限制时，执行的钩子函数 */
    const handleOnExceed = () => {
      proxy?.$message.error(`最大上传数量(${props.options.limit})已超出.`)
    }
    /** 覆盖默认的 Xhr 行为 */
    const handleHttpRequest = (options: UploadRequestOptions): any => {
      console.log('options :>> ', options, fileList)
      const file = fileList.value.find((m) => m.uid === options.file.uid)
      if (file) {
        file.status = 'uploading'
        file.size = options.file.size

        const config = {
          headers: {
            'Content-Type': 'multipart/form-data'
          },
          'Content-Type': 'multipart/form-data',
          timeout: 999999,
          onUploadProgress: (progressEvent: any) => {
            file.percentage = Number(((progressEvent.loaded / progressEvent.total) * 100).toFixed(2))
          }
        }

        const formdata = new FormData()
        formdata.append('file', options.file)

        // proxy?.$axios
        //   .post(options.action, formdata, config)
        //   .then((res) => {
        //     file.progress = 'success'
        //     options.onSuccess(res)
        //   })
        //   .catch((error) => {
        //     console.log('error :>> ', error)
        //     file.progress = 'warning'
        //     options.onError(error)
        //   })
      }
    }

    /** 超出上传文件数量时，隐藏上传按钮 */
    const hiddenUploadBtn = computed(() => {
      return fileList.value.length >= props.options.limit
    })

    watch(
      () => props.modelValue,
      (files: UploadFiles) => {
        if (files) {
          setFileList(files)
        }
      },
      { immediate: true }
    )

    /** 文件列表中文件类型 */
    const getFileType = (file: UploadFile) => {
      return file.raw?.type || 'unknown'
    }

    /** 获取文件类型图标 */
    const getIconByFileType = (file: UploadRawFile) => {
      const type = file.type
      if (type.includes('image/')) {
        return 'jpg'
      }
      if (type === 'application/msword') {
        return 'doc'
      }
      if (type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
        return 'doc'
      }
      if (type === 'application/vnd.ms-excel') {
        return 'xls'
      }
      if (type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
        return 'xls'
      }
      if (type === 'application/vnd.ms-powerpoint') {
        return 'ppt'
      }
      if (type === 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
        return 'ppt'
      }
      if (type === 'application/x-zip-compressed') {
        return 'zip'
      }
      if (type === 'application/octet-stream') {
        return 'zip'
      }
      return 'unknown'
    }

    return {
      isDetail,
      fieldRef,
      preview,
      imageIndex,
      showViewer,
      previewSrcList,
      fileList,
      hiddenUploadBtn,
      fileMaxSize,
      getFileType,
      getIconByFileType,
      downloadFile,
      closeViewer,
      handleRemove,
      handlePictureCardPreview,
      handleBeforeUpload,
      handleOnSuccess,
      handleOnError,
      handleOnExceed,
      handleHttpRequest
    }
  }
})
</script>
